package com.evil.application.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import co.elastic.clients.elasticsearch._types.aggregations.Aggregate;
import com.evil.application.api.RemoteApplicationReportingDataService;
import com.evil.application.enums.form.control.ControlCodeEnum;
import com.evil.application.enums.reporting.ReportingTargetTypeEnum;
import com.evil.application.enums.reporting.ReportingTypeEnum;
import com.evil.application.mapper.ApplicationInfoMapper;
import com.evil.application.mapper.ApplicationReportingMapper;
import com.evil.application.pojo.dto.form.control.ControlBaseInfoDTO;
import com.evil.application.pojo.dto.order.OrderPageReqDTO;
import com.evil.application.pojo.dto.permission.control.ControlPermissionDTO;
import com.evil.application.pojo.dto.reporting.ApplicationReportingDTO;
import com.evil.application.pojo.dto.reporting.FilterConfigDTO;
import com.evil.application.pojo.dto.reporting.ReportingTargetDTO;
import com.evil.application.pojo.dto.reporting.data.ReportingDataReqDTO;
import com.evil.application.pojo.dto.reporting.data.ReportingDataRespDTO;
import com.evil.application.pojo.dto.reporting.data.list.ReportingDataListReqDTO;
import com.evil.application.pojo.entity.ApplicationInfo;
import com.evil.application.pojo.entity.ApplicationProcessNode;
import com.evil.application.pojo.entity.ApplicationReporting;
import com.evil.application.service.*;
import com.evil.application.strategy.reporting.ReportingDataChartStrategy;
import com.evil.application.util.ApplicationReportingUtil;
import com.evil.application.util.ApplicationUtil;
import com.evil.common.account.util.LoginUtil;
import com.evil.common.application.dto.judge.JudgeOr;
import com.evil.common.application.dto.order.OrderPageDataRespDTO;
import com.evil.common.application.dto.permission.control.ControlPermissionSourceDTO;
import com.evil.common.application.enums.form.ControlPermissionSourceTypeEnum;
import com.evil.common.application.enums.permission.ControlVisibleEnum;
import com.evil.common.core.entity.PageModel;
import com.evil.common.core.util.StreamUtil;
import com.evil.common.core.enums.SwitchEnum;
import com.github.pagehelper.PageInfo;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;

/**
 * 应用报表数据服务
 *
 * @author liyang
 * @date 2022-08-08 00:00
 */
@Slf4j
@RestController
@AllArgsConstructor
public class ApplicationReportingDataServiceImpl implements RemoteApplicationReportingDataService {

    private final LoginUtil loginUtil;

    private final ApplicationReportingUtil applicationReportingUtil;

    private final ApplicationInfoMapper applicationInfoMapper;

    private final ApplicationReportingMapper applicationReportingMapper;

    private final ApplicationFormControlService applicationFormControlService;

    private final ApplicationProcessNodeService applicationProcessNodeService;

    private final ApplicationFilterGroupService applicationFilterGroupService;

    private final ControlPermissionService controlPermissionService;

    private final ReportingDataChartStrategy reportingDataChartStrategy;

    private final ElasticsearchService elasticsearchService;

    /**
     * 应用报表数据
     *
     * @param reportingDataReqDTO reportingDataReqDTO
     * @return ReportingDataRespDTO
     */
    @Override
    public ReportingDataRespDTO reportingData(ReportingDataReqDTO reportingDataReqDTO) {
        String reportingKey = reportingDataReqDTO.getReportingKey();
        ApplicationReportingDTO reportingDTO = applicationReportingUtil.appReportingInfo(reportingKey);
        ReportingTypeEnum reportingTypeEnum = ReportingTypeEnum.findById(reportingDTO.getReportingType());

        // 柱状表/折线图/饼状图 没有设置指标时，默认有数据总量指标
        if (reportingDTO.getReportingTargets().isEmpty()) {
            if (ReportingTypeEnum.DATA_TABLE != reportingTypeEnum) {
                reportingDTO.getReportingTargets().add(new ReportingTargetDTO().setTargetType(ReportingTargetTypeEnum.DATA_SUMMARY.getId()));
            }
        }

        // 分类统计V2
        List<JudgeOr> judgeOrs = applicationFilterGroupService.transformFilterQuery(reportingKey, reportingDataReqDTO.getFilterQuery());
        if (!judgeOrs.isEmpty()) {
            reportingDTO.setFilterStatus(SwitchEnum.YES.getId());
            FilterConfigDTO filterConfig = reportingDTO.getFilterConfig();
            if (CollectionUtil.isNotEmpty(filterConfig.getJudgeOrs())) {
                filterConfig.getJudgeOrs().addAll(judgeOrs);
            } else {
                filterConfig.setJudgeOrs(judgeOrs);
            }
        }

        Aggregate aggregations = elasticsearchService.orderDataSummary(reportingDTO);
        return reportingDataChartStrategy.calculation(reportingDTO, aggregations);
    }

    /**
     * 应用报表可见控件 基础信息
     *
     * @param reportingKey reportingKey
     * @return List
     */
    @Override
    public List<ControlBaseInfoDTO> reportingVisibleControlsBases(String reportingKey) {
        ApplicationReporting reporting = applicationReportingMapper.findByKey(reportingKey);

        ApplicationInfo applicationInfo = applicationInfoMapper.findById(reporting.getApplicationId());
        // 检查企业
        loginUtil.checkEnterpriseId(applicationInfo.getEnterpriseId());

        // 获取表单发布版控件
        List<ControlBaseInfoDTO> controlBases = applicationFormControlService.findReleaseBaseInfoByApp(applicationInfo, true);

        // 获取流程发布版节点
        List<ApplicationProcessNode> nodes = new ArrayList<>();
        try {
            nodes = applicationProcessNodeService.appReleaseNodes(applicationInfo.getApplicationId());
        } catch (Exception ignored) {
        }

        // 默认 需要过滤 订单列表
        Predicate<ControlBaseInfoDTO> filter = e -> ControlCodeEnum.orderListVisible(e.getControlCode());
        // 控件权限
        if (SwitchEnum.isOpen(reporting.getControlPermissionStatus())) {
            List<Long> controlIds = StreamUtil.transListT(controlBases, ControlBaseInfoDTO::getControlId);
            // 获取控件权限
            List<ControlPermissionDTO> controlPermissions = controlPermissionService.findBasesBySource(
                    new ControlPermissionSourceDTO(ControlPermissionSourceTypeEnum.REPORTING, reporting.getReportingId(), controlIds));
            // 可见控件权限
            List<Long> visibleControlIds = StreamUtil.transListFT(controlPermissions,
                    e -> ControlVisibleEnum.INVISIBLE.getId() != e.getVisible(), ControlPermissionDTO::getControlId);
            // 过滤 只保留可见控件
            filter = filter.and(e -> visibleControlIds.contains(e.getControlId()));
        }
        // 过滤
        controlBases = StreamUtil.filter(controlBases, filter);
        return ApplicationUtil.handleControlBases(controlBases, nodes);
    }

    /**
     * 应用报表数据
     *
     * @param reportingDataListReqDTO reportingDataListReqDTO
     * @return ReportingDataRespDTO
     */
    @Override
    public PageInfo<OrderPageDataRespDTO> reportingDataList(ReportingDataListReqDTO reportingDataListReqDTO) {
        String reportingKey = reportingDataListReqDTO.getReportingKey();
        PageModel<OrderPageReqDTO> pageModel = reportingDataListReqDTO.getPageModel();
        OrderPageReqDTO param = pageModel.getParam();

        ApplicationReportingDTO reportingDTO = applicationReportingUtil.appReportingInfo(reportingKey);

        List<JudgeOr> ors = param.getJudgeOrs();
        // 筛选条件 处理
        if (SwitchEnum.isOpen(reportingDTO.getFilterStatus())) {
            FilterConfigDTO filterConfig = reportingDTO.getFilterConfig();
            ors.addAll(filterConfig.getJudgeOrs());
        }
        // 应用筛选 处理
        ors.addAll(applicationFilterGroupService.transformFilterQuery(reportingKey, reportingDataListReqDTO.getFilterQuery()));

        param.setApplicationId(reportingDTO.getApplicationId());
        param.setJudgeOrs(ors);
        return elasticsearchService.orderDataPage(reportingDataListReqDTO);
    }
}
